package utils

import (
	"bytes"
	"encoding/json"
	"net/http"
	"sync"
	"time"
)

var (
	instance *TokenManager
	once     sync.Once
)

// GetTokenManager gets the singleton instance of TokenManager.
func GetTokenManager() *TokenManager {
	once.Do(func() {
		instance = &TokenManager{
			expiresIn:    24 * time.Hour,
			refreshTimer: time.NewTicker(1 * time.Hour),
		}
	})
	return instance
}

type TokenManager struct {
	token        string
	obtained     time.Time
	mutex        sync.RWMutex
	expiresIn    time.Duration
	refreshTimer *time.Ticker
}

type loginResponse struct {
	Token string `json:"token"`
}

func NewTokenManager(expiration time.Duration, refreshInterval time.Duration) *TokenManager {
	tm := &TokenManager{
		expiresIn:    expiration,
		refreshTimer: time.NewTicker(refreshInterval),
	}
	go tm.autoRefresh()
	return tm
}

func (m *TokenManager) requestNewToken() (string, error) {
	requestData := map[string]string{
		"username": "atomgit",
	}
	jsonData, err := json.Marshal(requestData)
	if err != nil {
		return "", err
	}

	resp, err := http.Post("http://47.105.42.242:8888/source/userLogin", "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	var response loginResponse
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return "", err
	}

	return response.Token, nil
}

func (m *TokenManager) autoRefresh() {
	for {
		<-m.refreshTimer.C
		m.mutex.RLock()
		needsRefresh := time.Since(m.obtained) > (m.expiresIn - time.Minute)
		m.mutex.RUnlock()

		if needsRefresh {
			newToken, err := m.requestNewToken()
			if err != nil {
				// 处理错误，例如记录日志
				continue
			}

			m.UpdateToken(newToken)
		}
	}
}

func (m *TokenManager) UpdateToken(newToken string) {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	m.token = newToken
	m.obtained = time.Now()
}

func (m *TokenManager) GetToken() (string, error) {
	m.mutex.RLock()
	tokenExpired := time.Since(m.obtained) > m.expiresIn
	m.mutex.RUnlock()

	if tokenExpired {
		// 如果token过期了，立即刷新
		if err := m.RefreshToken(); err != nil {
			return "", err
		}
	}

	m.mutex.RLock()
	defer m.mutex.RUnlock()
	return m.token, nil
}

func (m *TokenManager) RefreshToken() error {
	newToken, err := m.requestNewToken()
	if err != nil {
		return err
	}
	m.UpdateToken(newToken)
	return nil
}

func (m *TokenManager) StopAutoRefresh() {
	m.refreshTimer.Stop()
}
